package rdb

import (
	"context"
	"fmt"
	"github.com/redis/go-redis/v9"
	"sync"
)

type ZSetList interface {
	TopicKey(id any) string
	RedisClient() *redis.Client
	Add(id any, key string, score float64) error
	Adds(id any, keys map[string]float64) error
	Del(id any, key string) error
	Dels(id any, keys []string) error
	ZpopMin(id any) (ZsetItem, error)
	ZpopMax(id any) (ZsetItem, error)
	GetByIndex(id any, index int64) (ZsetItem, error)
	GetByIndexRange(id any, start int64, end int64) ([]ZsetItem, error)
	GetByIndexDESC(id any, index int64) (ZsetItem, error)
	GetByIndexRangeDESC(id any, start int64, end int64) ([]ZsetItem, error)
	GetByKey(id any, key string) (ZsetItem, error)
	Count(id any) (int64, error)
	GetAllKey(id any) ([]ZsetItem, error)
	ClearAll(id any) error
}

type _zsetList struct {
	Topic string        //主题
	Redis *redis.Client //Redis客户端
	RWL   sync.RWMutex  //读写锁
}

func NewZSetList(client *redis.Client, topic string) ZSetList {
	return &_zsetList{
		Topic: topic,
		Redis: client,
		RWL:   sync.RWMutex{},
	}
}

// TopicKey 返回默认生成的主题key
func (s *_zsetList) TopicKey(id any) string {
	return fmt.Sprint("ZSetList_", s.Topic, "_", id)
}

// RedisClient 返回绑定的Redis客户端
func (s *_zsetList) RedisClient() *redis.Client {
	return s.Redis
}

// Add 添加一个key
func (s *_zsetList) Add(id any, key string, score float64) error {
	s.RWL.Lock()
	err := s.Redis.ZAdd(context.Background(), s.TopicKey(id), redis.Z{
		Score:  score,
		Member: key,
	}).Err()
	s.RWL.Unlock()
	return err
}

// Adds 添加多个key
func (s *_zsetList) Adds(id any, keys map[string]float64) error {
	s.RWL.Lock()
	var temp []redis.Z
	for k, v := range keys {
		temp = append(temp, redis.Z{
			Score:  v,
			Member: k,
		})
	}
	err := s.Redis.ZAdd(context.Background(), s.TopicKey(id), temp...).Err()
	s.RWL.Unlock()
	return err
}

// Del 删除指定的key
func (s *_zsetList) Del(id any, key string) error {
	s.RWL.Lock()
	err := s.Redis.ZRem(context.Background(), s.TopicKey(id), key).Err()
	s.RWL.Unlock()
	return err
}

// Dels 删除指定的keys
func (s *_zsetList) Dels(id any, keys []string) error {
	s.RWL.Lock()
	var temp []any
	for _, d := range keys {
		temp = append(temp, d)
	}
	err := s.Redis.ZRem(context.Background(), s.TopicKey(id), temp...).Err()
	s.RWL.Unlock()
	return err
}

// ZpopMin 获取并且删除最小分数的
func (s *_zsetList) ZpopMin(id any) (ZsetItem, error) {
	s.RWL.Lock()
	result, err := s.Redis.ZPopMin(context.Background(), s.TopicKey(id)).Result()
	s.RWL.Unlock()
	if len(result) <= 0 {
		return ZsetItem{}, fmt.Errorf(fmt.Sprint(err))
	}
	return ZsetItem{
		Key:   fmt.Sprint(result[0].Member),
		Score: result[0].Score,
	}, err
}

// ZpopMax 获取并且删除最大分数的
func (s *_zsetList) ZpopMax(id any) (ZsetItem, error) {
	s.RWL.Lock()
	result, err := s.Redis.ZPopMax(context.Background(), s.TopicKey(id)).Result()
	s.RWL.Unlock()
	if len(result) <= 0 {
		return ZsetItem{}, fmt.Errorf(fmt.Sprint(err))
	}
	return ZsetItem{
		Key:   fmt.Sprint(result[0].Member),
		Score: result[0].Score,
	}, err
}

// GetByIndex 获取指定分数排名的成员，分数从小到大排序；下标为 index 的成员。
func (s *_zsetList) GetByIndex(id any, index int64) (ZsetItem, error) {
	s.RWL.RLock()
	result, err := s.Redis.ZRangeWithScores(context.Background(), s.TopicKey(id), index, index).Result()
	s.RWL.RUnlock()
	if len(result) <= 0 {
		return ZsetItem{}, fmt.Errorf(fmt.Sprint(err))
	}
	return ZsetItem{
		Key:   fmt.Sprint(result[0].Member),
		Score: result[0].Score,
	}, err
}

// GetByIndexRange 获取指定分数排名的成员，分数从小到大排序；下标为 start - end 的成员。
func (s *_zsetList) GetByIndexRange(id any, start int64, end int64) ([]ZsetItem, error) {
	s.RWL.RLock()
	result, err := s.Redis.ZRangeWithScores(context.Background(), s.TopicKey(id), start, end).Result()
	s.RWL.RUnlock()
	if len(result) <= 0 {
		return nil, fmt.Errorf(fmt.Sprint(err))
	}
	var arr []ZsetItem
	for _, d := range result {
		arr = append(arr, ZsetItem{
			Key:   fmt.Sprint(d.Member),
			Score: d.Score,
		})
	}
	return arr, err
}

// GetByIndexDESC 获取指定分数排名的成员，分数从大到小排序；下标为 index 的成员。
func (s *_zsetList) GetByIndexDESC(id any, index int64) (ZsetItem, error) {
	s.RWL.RLock()
	result, err := s.Redis.ZRevRangeWithScores(context.Background(), s.TopicKey(id), index, index).Result()
	s.RWL.RUnlock()
	if len(result) <= 0 {
		return ZsetItem{}, fmt.Errorf(fmt.Sprint(err))
	}
	return ZsetItem{
		Key:   fmt.Sprint(result[0].Member),
		Score: result[0].Score,
	}, err
}

// GetByIndexRangeDESC 获取指定分数排名的成员，分数从大到小排序；下标为 start - end 的成员。
func (s *_zsetList) GetByIndexRangeDESC(id any, start int64, end int64) ([]ZsetItem, error) {
	s.RWL.RLock()
	result, err := s.Redis.ZRevRangeWithScores(context.Background(), s.TopicKey(id), start, end).Result()
	s.RWL.RUnlock()
	if len(result) <= 0 {
		return nil, fmt.Errorf(fmt.Sprint(err))
	}
	var arr []ZsetItem
	for _, d := range result {
		arr = append(arr, ZsetItem{
			Key:   fmt.Sprint(d.Member),
			Score: d.Score,
		})
	}
	return arr, err
}

// GetByKey 获取指定key的成员
func (s *_zsetList) GetByKey(id any, key string) (ZsetItem, error) {
	s.RWL.RLock()
	result, err := s.Redis.ZScore(context.Background(), s.TopicKey(id), key).Result()
	s.RWL.RUnlock()
	return ZsetItem{
		Key:   key,
		Score: result,
	}, err
}

// Count 获取集合的成员数量
func (s *_zsetList) Count(id any) (int64, error) {
	s.RWL.RLock()
	defer s.RWL.RUnlock()
	result, err := s.Redis.ZCard(context.Background(), s.TopicKey(id)).Result()
	if err == nil || err == redis.Nil {
		return result, nil
	}
	return result, err
}

// GetAllKey 获取所有的key
func (s *_zsetList) GetAllKey(id any) ([]ZsetItem, error) {
	s.RWL.RLock()
	result, err := s.Redis.ZRangeWithScores(context.Background(), s.TopicKey(id), 0, -1).Result()
	s.RWL.RUnlock()
	if len(result) <= 0 {
		return nil, fmt.Errorf(fmt.Sprint(err))
	}
	var arr []ZsetItem
	for _, d := range result {
		arr = append(arr, ZsetItem{
			Key:   fmt.Sprint(d.Member),
			Score: d.Score,
		})
	}
	return arr, err
}

// ClearAll 清空所有的记录（直接删除key）
func (s *_zsetList) ClearAll(id any) error {
	s.RWL.Lock()
	err := s.Redis.Del(context.Background(), s.TopicKey(id)).Err()
	s.RWL.Unlock()
	return err
}
